﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using XMLGener.Interfaces;
using XMLGener.Data;

namespace XMLGener.Utils
{
    /// <summary>
    /// 
    /// </summary>
    public class XMLGenerDTDConverter:XMLSchemeConverter
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="logger"></param>
        public XMLGenerDTDConverter(XLogger logger)
        {
            this.logger = logger;
        }
        private XLogger logger;

        private string shortFileName = "";
        private string mainElementName = "";

        /// <summary>
        /// 
        /// </summary>
        /// <param name="doc"></param>
        /// <returns></returns>
        public bool generateScheme(XMLGenerDocument doc)
        {
            if (doc == null)
                return false;
            try
            {
                FileInfo fi = new FileInfo(doc.outFileFullPath);
                if (fi.Extension == "")
                {
                    logger.addErrorLog(this.GetType().ToString(), "Output file is not defined correctly. File exstension is missing.");
                    return false;
                }
                String schName = fi.Name;
                shortFileName = schName.Replace(fi.Extension, ".dtd");
                schName = DirectoriesUtil.combinePath(fi.DirectoryName, shortFileName);
                TextWriter tw = new StreamWriter(schName);


                XMLGenerRangeElement rangEl = doc.getMainElement();
                this.mainElementName = rangEl.name;
                XMLGenerElement elem = null;
                List<XMLGenerRangeElement> elemChilds = new List<XMLGenerRangeElement>();
                Stack<XMLGenerRangeElement> stack = new Stack<XMLGenerRangeElement>();
                XMLGenerRangeElement chElem;
                stack.Push(rangEl);
                int i;
                StringBuilder sb = new StringBuilder();
                StringBuilder sb2 = new StringBuilder();
                bool containsText = false;
                while (stack.Count > 0)
                {
                    rangEl = stack.Pop();
                    containsText = false;
                    elemChilds.Clear();
                    foreach (XMLGenerRangeElement chel in rangEl.childNodes)
                    {
                        if (chel != null)
                            elemChilds.Add(chel);
                        
                    }
                    i = 0;

                    while (i < elemChilds.Count)
                    {
                        chElem = elemChilds[i];
                        if (chElem is XMLGenerElements)
                        {
                            elemChilds.RemoveAt(i);
                            foreach (XMLGenerRangeElement chel in chElem.childNodes)
                            {
                                if (chel != null)
                                {
                                    elemChilds.Insert(i, chel);
                                };

                            }

                        }
                        else
                        {
                            i++;
                            stack.Push(chElem);
                        }

                    }
                    sb.Length = 0;
                    sb.Append("<!-- definition of ").Append(rangEl.name).Append(" -->");
                    tw.WriteLine(sb.ToString());
                    sb.Length = 0;
                    sb.Append("<!ELEMENT ").Append(rangEl.name).Append(" ");
                    sb2.Length = 0;
                    if (elemChilds.Count > 0)
                    {
                        sb.Append("(");
                        i = 0;
                        for (i = 0; i < elemChilds.Count; i++)
                        {
                            if (i > 0) sb.Append("|");
                            if (elemChilds[i] is XMLGenerTextNode)
                                containsText = true;
                            else
                                sb2.Append(elemChilds[i].name);

                        }
                        if (containsText)
                        {
                            if (sb2.Length > 0)
                                sb2.Insert(0, "|");
                            sb2.Insert(0, "#PCDATA");
                        }
                        sb.Append(sb2.ToString()).Append(")*");
                    }
                    else {
                        sb.Append(" EMPTY");    
                    }
                    sb.Append(" >");
                    if (rangEl is XMLGenerElement)
                    {
                        elem = rangEl as XMLGenerElement;
                        tw.WriteLine(sb.ToString());
                        sb.Length = 0;
                        sb.Append("<!ATTLIST ").Append(elem.name);
                        i = 0;
                        foreach (XMLGenerAttribute attr in elem.attributes)
                        {
                            if (attr is XMLGenerAttribute)
                            {
                                sb.Append("\n").Append(' ', 18);
                                sb.Append(attr.name).Append(" CDATA #IMPLIED");
                                i++;
                            }
                        }
                        sb.Append(" >\n");
                        if (i > 0)
                            tw.WriteLine(sb.ToString());
                    }
                    tw.WriteLine();
                }
                


                tw.Close();
            }
            catch (Exception)
            {
                return false;
            }


            return true;

        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string getSchemaHeaderForXML()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<!DOCTYPE ").Append(mainElementName);
            sb.Append(" SYSTEM \"").Append(shortFileName).Append("\" >");
            return sb.ToString();
            
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool schemaHeaderIsDocumentAttribute()
        {
            return false;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public XMLGenerDocument parseDocument(string fileName)
        {
            throw new NotImplementedException();
        }


    }
}
